import React, {
  forwardRef,
  useImperativeHandle,
  type JSX,
  type PropsWithChildren,
} from "react";
import {
  useForm,
  type FieldValues,
  type DefaultValues,
  type UseFormReturn,
  useFormContext,
} from "react-hook-form";
import type { CustomFieldConfig, IFieldConfig } from "./types";
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { cn } from "@/lib/utils";
import useFormFieldVisible from "./hooks/useFormFieldVisible";
import useFormFieldDisabled from "./hooks/useFormFieldDisabled";

export type SchemaFormProps<TFormValues extends FieldValues = FieldValues> =
  PropsWithChildren & {
    /** schema 定义 */
    fieldConfigs: IFieldConfig<TFormValues>[];
    defaultValues?: DefaultValues<TFormValues>;
    /** 提交回调 */
    onSubmit?: (data: TFormValues) => Promise<void> | void;
    className?: string;
  };

// eslint-disable-next-line react-refresh/only-export-components
function SchemaFormField<TFormValues extends FieldValues = FieldValues>(props: {
  fieldConfig: IFieldConfig<TFormValues>;
}) {
  const form = useFormContext<TFormValues>();
  const { fieldConfig } = props;
  const {
    visible: originVisible,
    disabled: originDisabled,
    name,
    rules,
    component = "Custom",
    className,
    label,
    description,
    props: fieldProps,
    required,
  } = fieldConfig;
  const visible = useFormFieldVisible<TFormValues>(originVisible);
  const disabled = useFormFieldDisabled<TFormValues>(originDisabled);

  if (!visible) {
    return null;
  }

  return (
    <FormField
      control={form.control}
      name={name}
      key={name}
      rules={{
        required: required
          ? {
              value: true,
              message: `${label ?? name} 是必填`,
            }
          : undefined,
        ...rules,
      }}
      render={({ field }) => {
        let control = null;
        // todo 类型保护优化
        if (component === "Custom") {
          const { render: RenderComponent } =
            fieldConfig as CustomFieldConfig<TFormValues>;
          control = (
            <RenderComponent {...field} {...fieldProps} disabled={disabled} />
          );
        } else if (component === "Input") {
          control = (
            <FormControl>
              <Input {...fieldProps} {...field} disabled={disabled} />
            </FormControl>
          );
        }
        return (
          <FormItem className={cn(className)}>
            <FormLabel>
              {required && <span className="text-red-400">*</span>}
              {label}
            </FormLabel>
            {control}
            {description && <FormDescription>{description}</FormDescription>}
            <FormMessage />
          </FormItem>
        );
      }}
    />
  );
}

// eslint-disable-next-line react-refresh/only-export-components
const SchemaFormInner = <TFormValues extends FieldValues = FieldValues>(
  props: SchemaFormProps<TFormValues>,
  ref: React.Ref<UseFormReturn<TFormValues>>
) => {
  const { defaultValues, fieldConfigs, onSubmit, className, children } = props;
  const form = useForm<TFormValues>({
    defaultValues,
  });

  useImperativeHandle(ref, () => form, [form]);

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit((values) => {
          onSubmit?.(values);
        })}
        className={cn("space-y-2", className)}
      >
        {fieldConfigs.map((fieldConfig) => (
          <SchemaFormField fieldConfig={fieldConfig} key={fieldConfig.name} />
        ))}
        {children}
      </form>
    </Form>
  );
};

// Export a forwardRef-wrapped component while preserving generic typing for callers
export default forwardRef(SchemaFormInner) as unknown as <
  TFormValues extends FieldValues = FieldValues,
>(
  props: SchemaFormProps<TFormValues> & {
    ref?: React.Ref<UseFormReturn<TFormValues>>;
  }
) => JSX.Element;
